package online.view.model;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.servlet.ServletResponse;

import online.model.UniModel;
import core.config.Factory;

/**
 * 単一化マップ
 *
 * @author Tadashi Nakayama
 */
final class SingleMap implements ViewMap {
	/** serialVersionUID */
	private static final long serialVersionUID = -378597890118091306L;

	/** ViewMap */
	private final ViewMap vm;
	/** 配列化処理項目 */
	private final ViewArrayMap array;

	/** レスポンス */
	private transient ServletResponse response;

	/**
	 * コンストラクタ
	 * @param val ViewMap
	 */
	public SingleMap(final ViewMap val) {
		this.vm = val;
		this.array = new ViewArrayMap(val);
	}

	/**
	 * @see java.util.Map#clear()
	 */
	@Override
	public void clear() {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see java.util.Map#containsKey(java.lang.Object)
	 */
	@Override
	public boolean containsKey(final Object key) {
		return this.vm.containsKey(Objects.toString(key, null));
	}

	/**
	 * @see java.util.Map#containsValue(java.lang.Object)
	 */
	@Override
	public boolean containsValue(final Object value) {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see java.util.Map#entrySet()
	 */
	@Override
	public Set<Entry<String, Serializable>> entrySet() {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see java.util.Map#get(java.lang.Object)
	 */
	@Override
	public Serializable get(final Object key) {
		if (ATTR_ARRAY.equals(key)) {
			return this.array;
		}

		Serializable obj = this.vm.get(key);
		if (UniModel.class.isInstance(obj)) {
			ViewMap vmap = Factory.create(ViewMap.class);
			vmap.setMap(UniModel.class.cast(obj).toMap());
			vmap.setResponse(this.response);
			obj = vmap;
		} else if (ViewList.class.isInstance(obj)) {
			if (!ViewList.class.cast(obj).isEmpty()) {
				obj = ViewList.class.cast(obj).get(0);
			} else {
				obj = null;
			}
		}

		return obj;
	}

	/**
	 * @see java.util.Map#isEmpty()
	 */
	@Override
	public boolean isEmpty() {
		return this.vm.isEmpty();
	}

	/**
	 * @see java.util.Map#keySet()
	 */
	@Override
	public Set<String> keySet() {
		return this.vm.keySet();
	}

	/**
	 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
	 */
	@Override
	public Serializable put(final String key, final Serializable value) {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see java.util.Map#putAll(java.util.Map)
	 */
	@Override
	public void putAll(final Map<? extends String, ? extends Serializable> t) {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see java.util.Map#remove(java.lang.Object)
	 */
	@Override
	public Serializable remove(final Object key) {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see java.util.Map#size()
	 */
	@Override
	public int size() {
		return this.vm.size();
	}

	/**
	 * @see java.util.Map#values()
	 */
	@Override
	public Collection<Serializable> values() {
		throw new UnsupportedOperationException();
	}

	/**
	 * @see online.view.model.ViewMap#setMap(java.util.Map)
	 */
	@Override
	public void setMap(final Map<String, Serializable> map) {
		this.vm.setMap(map);
	}

	/**
	 * @see online.view.model.ViewMap#getMap()
	 */
	@Override
	public Map<String, Serializable> getMap() {
		return this.vm.getMap();
	}

	/**
	 * @see online.view.model.ViewMap#setResponse(javax.servlet.ServletResponse)
	 */
	@Override
	public void setResponse(final ServletResponse val) {
		this.response = val;
		this.vm.setResponse(val);
	}

	/**
	 * 表示用マップ
	 *
	 * @author Tadashi Nakayama
	 * @version 1.0.0
	 */
	private static final class ViewArrayMap implements Map<String, Serializable>, Serializable {
		/** serialVersionUID */
		private static final long serialVersionUID = 1941090353339319732L;

		/** モデル */
		private final ViewMap model;

		/**
		 * コンストラクタ
		 *
		 * @param val マップオブジェクト
		 */
		public ViewArrayMap(final ViewMap val) {
			this.model = val;
		}

		/**
		 * @see java.util.Map#size()
		 */
		@Override
		public int size() {
			return this.model.size();
		}

		/**
		 * @see java.util.Map#clear()
		 */
		@Override
		public void clear() {
			throw new UnsupportedOperationException();
		}

		/**
		 * @see java.util.Map#isEmpty()
		 */
		@Override
		public boolean isEmpty() {
			return this.model.isEmpty();
		}

		/**
		 * @see java.util.Map#containsKey(java.lang.Object)
		 */
		@Override
		public boolean containsKey(final Object key) {
			return this.model.containsKey(Objects.toString(key, null));
		}

		/**
		 * @see java.util.Map#containsValue(java.lang.Object)
		 */
		@Override
		public boolean containsValue(final Object value) {
			throw new UnsupportedOperationException();
		}

		/**
		 * @see java.util.Map#values()
		 */
		@Override
		public Collection<Serializable> values() {
			throw new UnsupportedOperationException();
		}

		/**
		 * @see java.util.Map#putAll(java.util.Map)
		 */
		@Override
		public void putAll(final Map<? extends String, ? extends Serializable> t) {
			throw new UnsupportedOperationException();
		}

		/**
		 * @see java.util.Map#entrySet()
		 */
		@Override
		public Set<Entry<String, Serializable>> entrySet() {
			throw new UnsupportedOperationException();
		}

		/**
		 * @see java.util.Map#keySet()
		 */
		@Override
		public Set<String> keySet() {
			return this.model.keySet();
		}

		/**
		 * @see java.util.Map#get(java.lang.Object)
		 */
		@Override
		public Serializable get(final Object key) {
			Serializable obj = this.model.get(key);
			if (obj == null || UniModel.class.isInstance(obj)) {
				obj = new ViewList(Collections.EMPTY_LIST, null, false);
			} else if (!List.class.isInstance(obj)) {
				obj = new ViewList(Arrays.asList(obj), null, false);
			}
			return obj;
		}

		/**
		 * @see java.util.Map#remove(java.lang.Object)
		 */
		@Override
		public Serializable remove(final Object key) {
			throw new UnsupportedOperationException();
		}

		/**
		 * @param key キー
		 * @param value 値
		 * @return 既存値
		 * @see java.util.Map#put(java.lang.Object, java.lang.Object)
		 */
		@Override
		public Serializable put(final String key, final Serializable value) {
			throw new UnsupportedOperationException();
		}
	}
}
